#include <inttypes.h>
#include <stdarg.h>
#include <stdlib.h>

#include "rt.h"

static void
rt_log (struct runtime *rt, char const *fmt, ...)
{
  fprintf (stderr, "event[%" PRIu64 "]: ", rt->event_begin);

  va_list ap;
  va_start (ap, fmt);
  vfprintf (stderr, fmt, ap);
  va_end (ap);

  fprintf (stderr, "\n");
}

static func_task
run_ev (struct runtime *rt, struct event *ev)
{
  switch (ev->type)
    {
    case EVENT_OPEN:
      rt->fp = fopen (ev->via.open.path, "r");

      rt_log (rt, "open `%s' -> %p", ev->via.open.path, rt->fp);

      if (rt->fp == NULL)
        {
          rt_log (rt, "failed to open `%s'", ev->via.open.path);
          return ev->via.open.on_error;
        }
      else
        return ev->via.open.on_ok;

    case EVENT_READ:
      rt_log (rt, "read <- %p", ev->via.read.fp);

      rt->iolen = fread (rt->iobuf, 1, MC_IO_BUF, ev->via.read.fp);

      if (feof (ev->via.read.fp))
        return ev->via.read.on_eof;
      else if (ferror (ev->via.read.fp))
        return ev->via.read.on_error;
      else
        return ev->via.read.on_ok;

    case EVENT_CREATE:
      // TODO
      break;
    case EVENT_WRITE:
      // rt_log (stderr, "%s: write\n", loghdr);
      // rt->iolen = fwrite (rt->iobuf, 1, MC_IO_BUF, rt->fp);
      // TODO
      break;
    case EVENT_CLOSE:
      rt_log (rt, "close %p", rt->fp);
      fclose (ev->via.close.fp);

      return ev->via.close.then;
    }

  rt_log (rt, "unhandled event: %d", (int)ev->type);
  abort ();
}

void
rt_run (struct runtime *rt, func_task start, struct task_ctx *ctx)
{
  struct event *ev;

  if (!start (rt, ctx))
    return;

  while (true)
    {
      if (rt->event_begin >= rt->event_end)
        {
          rt_log (rt, "no more events");
          break;
        }

      while (rt->event_begin < rt->event_end)
        {
          func_task task
              = run_ev (rt, &rt->events[rt->event_begin & MC_EVENT_MASK]);

          rt->event_begin += 1;

          if (!task (rt, ctx))
            break;
        }
    }
}
